/**
 * Copyright © 2019 eqxiu.com 北京中网易企秀科技有限公司  All rights reserved.
 */
package com.siping.并发.黑马并发实战.自定义连接池;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * @author YangXu
 * @date 2022/3/3
 * @description:
 */

/**
 * 连接池
 * @param <T>
 */
public class ObjectPool<T> {
    /**
     * 空闲对象
     */
    private LinkedBlockingDeque<PoolObject<T>> idleObjects;
    /**
     * 所有的对象
     */
    private Map<Integer, PoolObject<T>> allObjects;
    /**
     * 池大小
     */
    private Integer poolSize;
    /**
     * 对象工厂，用于创建对象
     */
    private PoolObjectFactory<T> factory;

    public ObjectPool(Integer poolSize, PoolObjectFactory<T> factory) {
        this.poolSize = poolSize;
        this.factory = factory;
        idleObjects = new LinkedBlockingDeque<>(poolSize);
        allObjects = new ConcurrentHashMap<>();
    }

    /**
     * 从连接池里拿一个对象
     * @return
     */
    public T borrowObject() {
        PoolObject<T> p = null;
        while (true) {
            p = idleObjects.pollFirst();
            if (p != null) {
                System.out.println(Thread.currentThread().getName() + "获取到对象：" + p);
                return p.getObject();
            }
            synchronized (this) {
                if (poolSize > allObjects.size()) {
                    p = factory.makeObject();
                    allObjects.put(System.identityHashCode(p.getObject()), p);
                    idleObjects.push(p);
                } else {
                    try {
                        System.out.println(Thread.currentThread().getName() + "进入等待");
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 归还对象
     * @param obj
     */
    public void returnObject(T obj) {
        PoolObject<T> p = allObjects.get(System.identityHashCode(obj));
        if (p == null) {
            return;
        }
        System.out.println(Thread.currentThread().getName() + "归还对象：" + p);
        idleObjects.add(p);
        synchronized (this) {
            this.notifyAll();
        }
    }
}
